/**
 * @file demo_tcp.c
 * @brief 使用标准socket套接字客户端接口实现的 tcp demo.
 * @version 1.0
 * @date 2021-02-23
 * @copyright Copyright (c) 2021  河北骑士智能科技有限公司
 */

#include "zos_config.h"

#ifdef BOARD_USING_DEMO_TCP
#include "zos.h"

#define tcp_recv_len 1024

zos_task_t task_demo_tcp_handle = ZOS_NULL;

zos_uint8_t tcp_send_buf[50] = "This is a tcp client form QS-100 module\r\n";

zos_uint8_t tcp_url[50];

zos_uint32_t tcp_port;

void tcp_client(void *parameter)
{
    int ret;
    char *recv_data;
    struct hostent *host;
    int sock, bytes_received;
    struct sockaddr_in server_addr;
 
    /* 通过函数入口参数url获得host地址（如果是域名，会做域名解析）*/
    host = gethostbyname(tcp_url);
    /*分配用于存放接收数据的缓冲*/
    recv_data = zos_malloc(tcp_recv_len);
    if (recv_data == ZOS_NULL)
    {
        zos_printf("[demo_tcp] No memory\r\n");
        goto _exit;
    }
    /*创建一个socket，类型是SOCKET_STREAM，TCP类型*/
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        /*创建socket失败 */
        zos_printf("[demo_tcp] Socket error\r\n");
        /*释放接收缓冲*/
        zos_free(recv_data);
        goto _exit;
    }
    /*初始化预连接的服务端地址*/
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(tcp_port);
    server_addr.sin_addr = *((struct in_addr *)host->h_addr);
    memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
    /*连接到服务端*/
    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
    {
        /*连接失败*/
        zos_printf("[demo_tcp] Connect fail!\r\n");
        closesocket(sock);
        /*释放接收缓冲*/
        zos_free(recv_data);
        goto _exit;
    }
    while (1)
    {
        /*从sock连接中接收最大BUFSZ-1字节数据*/
        bytes_received = recv(sock, recv_data, tcp_recv_len - 1, 0);
        if (bytes_received < 0)
        {
            /*接收失败，关闭这个连接*/
            closesocket(sock);
            zos_printf("[demo_tcp] received error,close the socket.\r\n");
            /*释放接收缓冲*/
            zos_free(recv_data);
            break;
        }
        else if (bytes_received == 0)
        {
            /*打印recv函数返回值为0的警告信息*/
            zos_printf("[demo_tcp] Received warning,recv function return 0.\r\n");
            continue;
        }
        /*有接收到数据，把末端清零*/
        recv_data[bytes_received] = '\0';
        if (strncmp(recv_data, "q", 1) == 0 || strncmp(recv_data, "Q", 1) == 0)
        {
            /*如果是首字母是q或Q，关闭这个连接*/
            closesocket(sock);
            zos_printf("[demo_tcp] client recv a 'q' or 'Q',close the socket.\r\n");
            /*释放接收缓冲*/
            zos_free(recv_data);
            break;
        }
        else
        {
            /*在控制终端显示收到的数据*/
            zos_printf("[demo_tcp] Received data = %s ", recv_data);
        }
        /*发送数据到sock连接 */
        ret = send(sock, tcp_send_buf, strlen(tcp_send_buf), 0);
        if (ret < 0)
        {
            /*接收失败，关闭这个连接*/
            closesocket(sock);
            zos_printf("[demo_tcp] send error,close the socket.\r\n");
            zos_free(recv_data);
            break;
        }
        else if (ret == 0)
        {
            /*打印send函数返回值为0的警告信息*/
            zos_printf("[demo_tcp] Send warning,send function return 0.\r\n");
        }
    }

_exit:
    task_demo_tcp_handle = ZOS_NULL;
    zos_task_exit();
}



int demo_tcp(int argc, char **argv)
{
    /*接收到的参数小于3个*/
    if (argc < 3)
    {
        zos_printf("Usage: demo_tcp url port\r\n");
        zos_printf("Like: demo_tcp 192.168.12.44 5000\r\n");
        return ZOS_ERROR;
    }

    zos_printf("ip = %s  port = %s\r\n",argv[1],argv[2]);
    strncpy(tcp_url,argv[1],strlen(argv[1]));
    tcp_port = strtoul(argv[2], 0, 10);

	/*创建TCP任务，任务函数使用刚才获取到的IP和port信息，连接到服务器*/
    task_demo_tcp_handle = zos_task_create("demo_tcp",tcp_client,ZOS_NULL,1024,task_Priority_Normal);
    if(task_demo_tcp_handle == ZOS_NULL)
    {
        zos_printf("task_demo_tcp_handle create failed\r\n");
    }
	return ZOS_EOK;
    
}
#include "shell.h"

SHELL_EXPORT_CMD(demo_tcp,demo_tcp, tcp demo);

#endif
